package com.kaili.db.runner;

import com.alibaba.druid.filter.config.ConfigTools;
import com.kaili.common.util.CommonConstant;
import com.kaili.common.util.CommonUtil;
import com.kaili.db.bean.DataSourceBean;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.jdbc.ScriptRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import java.io.*;
import java.nio.charset.Charset;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 项目启动的时候执行
 */
@Component
public class MyApplicationRunner implements ApplicationRunner {
    private Logger logger = LoggerFactory.getLogger(MyApplicationRunner.class);

    /**
     * 查询动态数据源SQL
     */
    private String sql = "select driver_class_name,url,username,password from sys_datasource where type='write'";

    /**
     * 普通SQL语句脚本
     */
    private String sqlName = "sqlBatch.sql";

    /**
     * 函数或存储过程脚本
     */
    private String procedureName = "procedureBatch.sql";

    /**
     * 脚本执行日志文件路径
     */
    private String logFileName = "logs"+File.separator+"kaili-db-sql.log";

    /**
     * ScriptRunner日志输出对象
     */
    private PrintWriter printWriter = null;

    @Value("${spring.datasource.url}")
    private String url;

    @Value("${spring.datasource.username}")
    private String user;

    @Value("${spring.datasource.password}")
    private String password;

    @Value("${spring.datasource.driverClassName}")
    private String driverClass;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        try {
            initPrintWriter();

            Connection conn = null;
            Statement stmt = null;
            ScriptRunner runner = null;
            int i = 0;
            List<DataSourceBean> list = getMulDataSource();
            for(DataSourceBean bean : list){
                this.printWriter.println("------------------------------------------正在执行第"+(++i)+"个数据库 "+bean.getUrl()+"------------------------------------------");

                try {
                    Class.forName(bean.getJdbcDriver());
                    conn=DriverManager.getConnection(bean.getUrl(),bean.getUserName(),CommonUtil.druidDecrypt(bean.getPassword()));
                    stmt=conn.createStatement();
                    runner=new ScriptRunner(conn);
                    if(this.printWriter != null){
                        runner.setLogWriter(this.printWriter);
                        runner.setErrorLogWriter(this.printWriter);
                    }
                    Resources.setCharset(Charset.forName("UTF-8"));
                    // 1.执行普通SQL脚本
                    runner.runScript(Resources.getResourceAsReader(sqlName));

                    // 2.执行函数或存储过程
                    runner.setDelimiter("DELIMITER ;");//执行函数的时候，需要取消注释
                    runner.runScript(Resources.getResourceAsReader(procedureName));
                }
                catch(Exception e){
                    this.printWriter.println("执行脚本异常"+e.getMessage());
                }
                finally{
                    if(runner!=null){
                        runner.closeConnection();
                    }
                    if(stmt!=null){
                        stmt.close();
                    }
                    if(conn!=null){
                        conn.close();
                    }
                }
            }
        } catch (IOException e) {
            logger.info("io异常",e);
        } catch (SQLException e) {
            logger.info("sql异常",e);
        }catch (Exception e) {
            logger.info("其它异常",e);
        }
    }

    /**
     * 数据所有数据源
     * @return
     * @throws Exception
     */
    private List<DataSourceBean> getMulDataSource()throws Exception{
        List<DataSourceBean> list = new ArrayList<DataSourceBean>();
        Connection conn = null;
        Statement stmt = null;
        try {
            Class.forName(driverClass);
            conn=DriverManager.getConnection(url,user, CommonUtil.druidDecrypt(password));
            stmt=conn.createStatement();
            ResultSet rs = stmt.executeQuery(sql);
            while (rs.next()) {
                list.add(new DataSourceBean(rs.getString(1), rs.getString(2), rs.getString(3), rs.getString(4)));
            }
        } finally{
            if(stmt!=null){
                stmt.close();
            }
            if(conn!=null){
                conn.close();
            }
        }

        return list;
    }

    /**
     * 获取日志打印对象
     * @return
     */
    private void initPrintWriter(){
        FileWriter fw = null;
        try{
            fw= new FileWriter(logFileName, false);
            this.printWriter = new PrintWriter(fw);
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}
